package com.naiterui.ehp.bs.doctor.service.record.impl;

import java.util.Date;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.naiterui.ehp.bp.domain.City;
import com.naiterui.ehp.bp.support.exception.BusinessException;
import com.naiterui.ehp.bp.support.utils.JsonMapper;
import com.naiterui.ehp.bp.utils.beans.BeanUtil;
import com.naiterui.ehp.bs.doctor.domain.RecordUserInfo;
import com.naiterui.ehp.bs.doctor.domain.RecordWorkContract;
import com.naiterui.ehp.bs.doctor.domain.RecordWorkInfo;
import com.naiterui.ehp.bs.doctor.domain.StandardDict;
import com.naiterui.ehp.bs.doctor.exception.ExceptionCodes;
import com.naiterui.ehp.bs.doctor.repository.ICityRepository;
import com.naiterui.ehp.bs.doctor.repository.IRecordUserInfoRepository;
import com.naiterui.ehp.bs.doctor.repository.IRecordWorkContractRepository;
import com.naiterui.ehp.bs.doctor.repository.IRecordWorkInfoRepository;
import com.naiterui.ehp.bs.doctor.repository.IStandardDictRepository;
import com.naiterui.ehp.bs.doctor.service.record.IRecordInfoService;
import com.naiterui.ehp.bs.doctor.service.record.ISupervisePlatformService;
import com.naiterui.ehp.bs.doctor.vo.record.RecordAuditResultVO;
import com.naiterui.ehp.bs.doctor.vo.record.RecordInfoVO;
import com.naiterui.ehp.bs.doctor.vo.record.RecordResultVO;
import com.naiterui.ehp.bs.doctor.vo.record.RecordUserInfoVO;
import com.naiterui.ehp.bs.doctor.vo.record.RecordWorkContractVO;
import com.naiterui.ehp.bs.doctor.vo.record.RecordWorkInfoVO;
import com.naiterui.ehp.bs.doctor.vo.record.ReocrdUserBaseInfoVO;

import cn.hutool.core.collection.CollectionUtil;

/**
 * @author guoyongxiang
 * @date 2020/2/17 16:54
 * @since 1.0.0
 */
@Service
public abstract class AbstractRecordInfoServiceImpl implements IRecordInfoService {

    private static final Logger LOGGER = LoggerFactory.getLogger(AbstractRecordInfoServiceImpl.class);

    @Autowired
    private IRecordUserInfoRepository recordUserInfoRepository;
    @Autowired
    private IRecordWorkInfoRepository recordWorkInfoRepository;
    @Autowired
    private IRecordWorkContractRepository recordWorkContractRepository;
    @Autowired
    private ICityRepository cityRepository;
    @Autowired
    private IStandardDictRepository standardDictRepository;
    @Autowired
    private ISupervisePlatformService supervisePlatformService;

    @Autowired
    @Qualifier("recordInfoDoctorServiceImpl")
    private RecordInfoDoctorServiceImpl recordInfoDoctorService;

    private static final String USER_TYPE_DR_PRE = "DR";
    private static final String USER_TYPE_PH_PRE = "PH";

    public static final String TITLE_SUFFIX = "专用章";

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateUserInfo(RecordInfoVO recordInfoVO, String operator) throws BusinessException {
        ReocrdUserBaseInfoVO baseInfoVO = recordInfoVO.getUserBaseInfo();

        // 更新用户基础信息
        String userCode = this.updateBaseInfo(recordInfoVO, operator);

        // 更新用户详细信息
        this.updateRecordUserInfo(baseInfoVO.getUserId(), baseInfoVO.getUserType(), recordInfoVO.getUserInfo(), operator);

        // 更新工作经历
        this.updateRecordWorkInfo(userCode, recordInfoVO.getWorkInfos(), operator);

        // 更新聘任合同
        this.updateRecordWorkContract(userCode, recordInfoVO.getWorkContracts(), operator);

        if (RecordInfoVO.ACTION_APPLY_RECORD.equals(recordInfoVO.getAction()) && RecordUserInfo.USER_TYPE_DR.equals(baseInfoVO.getUserType())) {
            RecordUserInfo userInfo = this.recordUserInfoRepository.findByUserIdAndUserType(baseInfoVO.getUserId(), RecordUserInfo.USER_TYPE_DR);
            if (RecordUserInfo.STATUS_UNAPPLY.equals(userInfo.getStatus()) || RecordUserInfo.STATUS_FAILED.equals(
                    userInfo.getStatus()) || RecordUserInfo.STATUS_HANG
                    .equals(userInfo.getStatus())) {
                LOGGER.info("提交备案平台 userCode:{}, name:{}, operator:{}", userCode, baseInfoVO.getName(), operator);
                this.supervisePlatformService.syncRecordInfo(userCode, baseInfoVO.getUserType(), recordInfoVO);
                userInfo.setStatus(RecordUserInfo.STATUS_APPLYING);
                userInfo.setChangedAt(new Date());
                userInfo.setChangedBy(operator);
                this.recordUserInfoRepository.update(userInfo);
            }
        }
    }

    @Override
    public void saveCallback(RecordResultVO resultVO) throws BusinessException {
        // 校验账户信息
        boolean verify = this.supervisePlatformService.callbackVerify(resultVO.getHisId(), resultVO.getUname(), resultVO.getPwd());
        if (!verify) {
            LOGGER.warn("备案平台回调，账户信息校验失败 hisId:{}, uname:{}, pwd:{}", resultVO.getHisId(), resultVO.getUname(), resultVO.getPwd());
            throw new BusinessException(ExceptionCodes.PARAM_ERROR);
        }
        // 更新审核状态
        List<RecordAuditResultVO> auditResultVOS = JsonMapper.toList(resultVO.getData(), RecordAuditResultVO.class);
        for (RecordAuditResultVO auditVO : auditResultVOS) {
            String userCode = auditVO.getIn_doc_code();

            Integer status;
            switch (auditVO.getRecord_flag()) {
                case RecordAuditResultVO.RECORD_FLAG_PASS:
                    status = RecordUserInfo.STATUS_PASS;
                    break;
                case RecordAuditResultVO.RECORD_FLAG_FAILED:
                    status = RecordUserInfo.STATUS_FAILED;
                    break;
                case RecordAuditResultVO.RECORD_FLAG_HANG:
                    status = RecordUserInfo.STATUS_HANG;
                    LOGGER.warn("备案平台回调，用户审核状态挂起 userCode:{}", userCode);
                    break;
                default:
                    LOGGER.warn("备案平台回调，未知状态 userCode:{}, record_flag:{}", userCode, auditVO.getRecord_flag());
                    throw new BusinessException(ExceptionCodes.PARAM_ERROR);
            }

            RecordUserInfo userInfo = this.recordUserInfoRepository.findByUserCode(userCode);
            if (userInfo == null) {
                LOGGER.warn("备案平台回调，用户不存在 userCode:{}, record_flag:{}", userCode, auditVO.getRecord_flag());
                throw new BusinessException(ExceptionCodes.PARAM_ERROR);
            }
            userInfo.setStatus(status);
            userInfo.setChangedAt(new Date());
            userInfo.setChangedBy("监管平台");
            this.recordUserInfoRepository.update(userInfo);

            if (RecordUserInfo.USER_TYPE_DR.equals(userInfo.getUserType())) {
                this.recordInfoDoctorService.updateCallbackAfter(userInfo);
            } else {
                // TODO 药师
            }
        }
    }

    /**
     * 更新用户基本信息
     *
     * @param baseInfoVO
     * @param operator
     *
     * @return
     *
     * @throws BusinessException
     */
    protected abstract String updateBaseInfo(RecordInfoVO baseInfoVO, String operator) throws BusinessException;

    /**
     * 生成用户编码
     *
     * @param userId
     * @param userType
     *
     * @return
     *
     * @throws BusinessException
     */
    protected String getUserCode(Long userId, Integer userType) throws BusinessException {
        if (RecordUserInfo.USER_TYPE_DR.equals(userType)) {
            return USER_TYPE_DR_PRE + "_" + userId;
        } else if (RecordUserInfo.USER_TYPE_PH.equals(userType)) {
            return USER_TYPE_PH_PRE + "_" + userId;
        } else {
            LOGGER.warn("未知的用户类型 userId:{}, userType:{}", userId, userType);
            throw new BusinessException(ExceptionCodes.PARAM_ERROR, "未知的用户类型");
        }
    }

    /**
     * 更新用户详细信息
     *
     * @param userId
     * @param userType
     * @param userInfoVO
     * @param operator
     *
     * @throws BusinessException
     */
    private void updateRecordUserInfo(Long userId, Integer userType, RecordUserInfoVO userInfoVO, String operator) throws BusinessException {
        RecordUserInfo userInfo = this.recordUserInfoRepository.findByUserIdAndUserType(userId, userType);
        boolean create = false;
        if (userInfo == null) {
            userInfo = new RecordUserInfo();
            userInfo.setUserId(userId);
            userInfo.setUserType(userType);
            String userCode = this.getUserCode(userId, userType);
            userInfo.setUserCode(userCode);
            userInfo.setStatus(RecordUserInfo.STATUS_UNAPPLY);
            userInfo.setCreatedAt(new Date());
            userInfo.setCreatedBy(operator);
            create = true;
        }
        // 复制
        BeanUtil.copyPropertiesIgnoreNull(userInfoVO, userInfo);

        // 民族
        if (userInfo.getNationCode() != null) {
            StandardDict standardDict = this.standardDictRepository.findByCodeAndType(userInfo.getNationCode(), StandardDict.TYPE_NATION);
            userInfo.setNationName(standardDict.getName());
        }

        if (userInfoVO.getCityId() != null) {
            userInfo.setCityId(userInfoVO.getCityId());
            City city = this.cityRepository.get(userInfoVO.getCityId());
            String cityName = city.getParentName() + city.getName();
            cityName = cityName.replaceAll(",", "").replaceAll("中国", "");
            userInfo.setAddress(cityName);
            userInfoVO.setAddress(cityName);
        }

        userInfo.setChangedAt(new Date());
        userInfo.setChangedBy(operator);
        if (create) {
            this.recordUserInfoRepository.save(userInfo);
        } else {
            this.recordUserInfoRepository.update(userInfo);
        }
    }

    /**
     * 更新用户工作经历
     *
     * @param userCode
     * @param workInfosVO
     * @param operator
     */
    private void updateRecordWorkInfo(String userCode, List<RecordWorkInfoVO> workInfosVO, String operator) {
        if (CollectionUtil.isEmpty(workInfosVO)) {
            return;
        }
        this.recordWorkInfoRepository.removeByUserCode(userCode);
        workInfosVO.stream().forEach(w -> {
            RecordWorkInfo recordWorkInfo = new RecordWorkInfo();
            BeanUtils.copyProperties(w, recordWorkInfo);
            recordWorkInfo.setUserCode(userCode);
            recordWorkInfo.setCreatedAt(new Date());
            recordWorkInfo.setCreatedBy(operator);
            recordWorkInfo.setChangedAt(new Date());
            recordWorkInfo.setChangedBy(operator);
            this.recordWorkInfoRepository.save(recordWorkInfo);
        });

    }

    /**
     * 更新用户合同信息
     *
     * @param userCode
     * @param workContractsVO
     * @param operator
     */
    private void updateRecordWorkContract(String userCode, List<RecordWorkContractVO> workContractsVO, String operator) {
        if (CollectionUtil.isEmpty(workContractsVO)) {
            return;
        }
        this.recordWorkContractRepository.removeByUserCode(userCode);
        workContractsVO.forEach(w -> {
            RecordWorkContract recordWorkContract = new RecordWorkContract();
            BeanUtils.copyProperties(w, recordWorkContract);
            recordWorkContract.setUserCode(userCode);
            recordWorkContract.setCreatedAt(new Date());
            recordWorkContract.setCreatedBy(operator);
            recordWorkContract.setChangedAt(new Date());
            recordWorkContract.setChangedBy(operator);
            this.recordWorkContractRepository.save(recordWorkContract);
        });

    }
}
